package com.gzxx.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

/**
 * @author MAX
 * @date 2020/7/23 10:06 上午
 * Jwt工具类
 */
@Data
@Slf4j
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtOperator {

    /**
     * 秘钥
     **/
    private String secret;

    /**
     * 有效期，单位秒,默认1周
     **/
    private Long expirationTimeInSecond;

    /**
     * 计算token的过期时间
     *
     * @return 过期时间
     */
    public Date getExpirationTime() {
        return new Date(System.currentTimeMillis() + this.expirationTimeInSecond * 1000);
    }

    /**
     * token生成
     *
     * @param claims 自定义信息
     * @return token
     */
    public String generateToken(Map<String, Object> claims) {
        Date createdTime = new Date();

        byte[] secretBytes = secret.getBytes();
        SecretKey secretKey = Keys.hmacShaKeyFor(secretBytes);

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(createdTime)
                .setExpiration(getExpirationTime())
                .signWith(secretKey, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 从token中获取claim
     *
     * @param token token
     * @return Claims
     */
    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(this.secret.getBytes())
                .parseClaimsJws(token)
                .getBody();

    }

    /**
     * 获取token的过期时间
     *
     * @param token token
     * @return Expiration Date
     */
    public Date getExpirationDateFromToken(String token) {
        return getClaimsFromToken(token)
                .getExpiration();
    }

    /**
     * 判断token是否过期
     *
     * @param claims claims
     * @return 已过期返回true，未过期返回false
     */
    private Boolean isTokenExpired(Claims claims) {
        Date expiration = claims.getExpiration();
        return expiration.before(new Date());
    }

    /**
     * 判断token是否非法
     *
     * @param token token
     * @return 未过期返回true，否则返回false
     */
    public Claims parseToken(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            if(isTokenExpired(claims)) {
                throw new RuntimeException("token已过期");
            }

            return claims;
        }catch (Exception e) {
            log.error("token parse error", e);
            throw new RuntimeException("token解析异常");
        }
    }

}
